<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\storage;

interface IFile
{
  public function getDirectory();
  public function getFile($sKey);

  public function isFile($sKey);
  public function checkFile($sKey);
}

class ContainerFile extends Base implements IFile, IConcrete
{
  public function get($sKey)
  {
    if ($this->checkFile($sKey))
    {
      $sFile = $this->getFile($sKey);
      $sContent = \file_get_contents($sFile);
      return $sContent;
    }
    return \FALSE;
  }

  public function insert($sKey, $sValue)
  {
    try
    {
      //just insert if file not found
      $sFile = $this->getFile($sKey);
      $this->checkFile($sKey);
    }
    catch (\crcl\base\storage\Exception $e)
    {
      if ($e->getCode() == Exception::ERROR_NOTFOUND)
      {
        \file_put_contents($sFile, $sValue);
        return \TRUE;
      }
      else
      {
        throw $e;
      }
    }
    //if we get here, file already exists
    throw new Exception(
      'Key does already exist',
      Exception::ERROR_ALREADYEXISTS,
      array('key' => $sKey));
  }

  public function update($sKey, $sValue)
  {
    //just update if file found
    if ($this->checkFile($sKey))
    {
      $sFile = $this->getFile($sKey);
      \file_put_contents($sFile, $sValue);
      return \TRUE;
    }
    return \FALSE;
  }

  public function set($sKey, $sValue)
  {
    try
    {
      $this->insert($sKey, $sValue);
    }
    catch (Exception $e)
    {
      if ($e->getCode() == Exception::ERROR_ALREADYEXISTS)
      {
        $this->update($sKey, $sValue);
      }
      else
      {
        throw $e;
      }
    }
  }

  public function delete($sKey)
  {
    if ($this->checkFile($sKey))
    {
      $sFile = $this->getFile($sKey);
      \unlink($sFile);
    }
  }

  public function getDirectory()
  {
    $sRoot = \crcl\base\Config::reader()
             ->setDefault(
                 \crcl\base\Config::reader('ini:///%DIR_BASE_CONFIGS%config.%TIER%.ini')
                 ->setDefault(\FALSE)
                 ->get(self::CONFIG_DOMAIN, self::CONFIG_KEY_ROOT))
             ->get(self::CONFIG_DOMAIN, self::CONFIG_KEY_ROOT);
    $sDir = \crcl\base\String::getInstance($sRoot)->doEndWith('/');
    $sDir .= \crcl\base\Application::getIdentifier();
    $sDir = \crcl\base\String::getInstance($sDir)->doEndWith('/');
    if (!\file_exists($sDir))
    {
      \mkdir($sDir, 0777, \TRUE); //recursive directory creation
    }

    return $sDir;
  }

  public function getFile($sKey)
  {
    $sDir = $this->getDirectory();
    $sFile = $sDir . $sKey;
    if (\strpos($sKey, '/') !== \FALSE)
    {
      $sDir = \crcl\base\File::getInstance($sFile)->getDirectory();
      if (!\file_exists($sDir))
      {
        \mkdir($sDir, 0777, \TRUE); //recursive directory creation
      }
    }
    return $sFile;
  }

  public function isFile($sKey)
  {
    $sFile = $this->getFile($sKey);
    if (\file_exists($sFile))
    {
      return \TRUE;
    }
    return \FALSE;
  }

  public function checkFile($sKey)
  {
    $bCheck = $this->isFile($sKey);
    if (!$bCheck)
    {
      throw new Exception(
        'File not found',
        Exception::ERROR_NOTFOUND,
        array('key' => $sKey, 'file' => $this->getFile($sKey)));
    }
    return \TRUE;
  }

  /** PRIVATE *************************************************************************************/

  const CONFIG_DOMAIN = 'storage_file';
  const CONFIG_KEY_ROOT = 'root';
}

